package com.dj.mingkong.admin.biz.service.system.impl;

import com.dj.mingkong.admin.biz.controller.system.vo.request.UserRoleUpdateVo;
import com.dj.mingkong.admin.biz.controller.system.vo.response.UserRoleVo;
import com.dj.mingkong.admin.biz.repository.database.system.RoleRepository;
import com.dj.mingkong.admin.biz.repository.database.system.UserRepository;
import com.dj.mingkong.admin.biz.repository.database.system.UserRoleRepository;
import com.dj.mingkong.admin.biz.service.system.UserRoleService;
import com.dj.mingkong.common.enums.RoleEnum;
import com.dj.mingkong.common.enums.StatusEnum;
import com.dj.mingkong.common.exception.ValidateException;
import com.dj.mingkong.common.infrastructure.base.eo.BaseEo;
import com.dj.mingkong.common.infrastructure.eo.database.system.RoleEo;
import com.dj.mingkong.common.infrastructure.eo.database.system.UserRoleEo;
import com.dj.mingkong.common.util.AssertUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;

/**
 * 用户角色服务实现类
 *
 * @author zenglonghui
 * @date: 2022/8/16 9:32
 */
@Slf4j
@Service("userRoleService")
public class UserRoleServiceImpl implements UserRoleService {
    @Resource
    private UserRoleRepository userRoleRepository;
    @Resource
    private UserRepository userRepository;
    @Resource
    private RoleRepository roleRepository;

    @Override
    public UserRoleVo listByUserId(Long userId) {
        final List<UserRoleEo> userRoleEos = userRoleRepository.listByUserId(userId);
        if (userRoleEos.isEmpty()) {
            return UserRoleVo.builder().userId(userId).roleIdList(Collections.emptyList()).build();
        }
        return UserRoleVo.builder().userId(userId)
                .roleIdList(userRoleEos.stream().map(UserRoleEo::getRoleId).toList())
                .build();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateByUserId(UserRoleUpdateVo updateVo) {
        checkUserRoleVo(updateVo);
        final List<Long> roleIdList = updateVo.getRoleIdList();
        final List<UserRoleEo> userRoleEos = userRoleRepository.listByUserId(updateVo.getUserId());
        if (CollectionUtils.isNotEmpty(userRoleEos)) {
            final RoleEo roleEo = roleRepository.oneByCode(RoleEnum.USER.getCode());
            final List<Long> addList = roleIdList.stream().filter(r ->
                    !userRoleEos.stream().map(UserRoleEo::getRoleId).toList().contains(r)).toList();
            final List<Long> delList = userRoleEos.stream().filter(r ->
                            !roleIdList.contains(r.getRoleId()) && !r.getRoleId().equals(roleEo.getId()))
                    .map(BaseEo::getId).toList();
            saveUserRole(addList, updateVo.getUserId());
            userRoleRepository.deleteByIds(delList);
        } else {
            saveUserRole(roleIdList, updateVo.getUserId());
        }
    }

    private void checkUserRoleVo(UserRoleUpdateVo updateVo) {
        AssertUtils.isNotNull(userRepository.getById(updateVo.getUserId()), "userId invalid");
        final List<Long> roleIdList = updateVo.getRoleIdList();
        final Long count = roleRepository.lambdaQuery()
                .in(BaseEo::getId, roleIdList).eq(RoleEo::getStatus, StatusEnum.VALID.getIntVal()).count();
        if (roleIdList.size() != count) {
            throw new ValidateException("roleId invalid");
        }
    }

    private void saveUserRole(List<Long> roleIdList, Long userId) {
        if (CollectionUtils.isNotEmpty(roleIdList)) {
            final List<UserRoleEo> userRoleEos = roleIdList.stream().map(r ->
                    UserRoleEo.builder().roleId(r).userId(userId).build()).toList();
            userRoleRepository.saveBatch(userRoleEos);
        }
    }
}
